package com.common.config;


import com.common.base.BaseConstant;
import com.common.util.LoginUtil;
import com.entity.sys.SysRole;
import com.entity.sys.SysUser;
import fuhua.com.anno.CheckPermission;
import fuhua.com.util.BaseUtil;
import fuhua.com.vo.ExceptionVo;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 自定义拦截器，实现注解鉴权和token验证
 */
public class CustomInterceptor implements HandlerInterceptor {

    /** 设置响应头部信息 */
    private void setHeader(HttpServletRequest request,HttpServletResponse response){
        response.setHeader( "Set-Cookie" , "cookiename=httponlyTest;Path=/;Domain=domainvalue;Max-Age=seconds;HTTPOnly");
        response.setHeader( "Content-Security-Policy" , "default-src 'self'; script-src 'self'; frame-ancestors 'self'");
        response.setHeader("Access-Control-Allow-Origin", (request).getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Referrer-Policy","no-referrer");
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
    }

    /** token有效期刷新和定期刷新 */
    private void refreshToken(HttpServletResponse response,String tokenValue){
        //判断token的创建时间是否大于2小时，如果是的话则需要刷新token
        long time = System.currentTimeMillis() - LoginUtil.getCreateTime(tokenValue);
        long hour = time/1000/(60 * 60);
        if (hour>2){
            // TODO 获取当前用户信息，重新登录，生成新的token，将新token设置到响应头中
            SysUser user = LoginUtil.getLoginUser(tokenValue);
            // TODO 这里重新登录（会把旧登录删除），生成新的token
            String newToken = LoginUtil.login(user);
            response.setHeader(BaseConstant.tokenHeader, newToken);
        }
        long tokenTimeout = LoginUtil.getTimeOut(tokenValue);// 获取过期时间
        if (tokenTimeout != -1){ // token没过期，过期时间不是-1的时候，每次请求都刷新过期时间
            LoginUtil.updateTimeOut(tokenValue);
        }
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
        setHeader(request,response);
        // 获取当前token（这个token获取的是请求头的token，也可以用 request 获取）
        String tokenValue = LoginUtil.getToken(request);
        if (!checkPermisson(handler,tokenValue)){ // 鉴权
            throw new ExceptionVo(-1,"没有操作权限");
        }
        refreshToken(response,tokenValue);
        return true;
    }

    /** 校验注解权限或角色 */
    private boolean checkPermisson(Object handler,String tokenValue){
        boolean flag = true;
        if (handler instanceof HandlerMethod){
            // 获得请求的方法
            Method method = ((HandlerMethod) handler).getMethod();
            // 获得该方法上面的注解，如果没有注解，直接返回true,通过
            CheckPermission annotation = method.getAnnotation(CheckPermission.class);
            if (annotation != null) {
                String[] perm = annotation.perm(); // 注解上指定的权限标识
                String[] role = annotation.role(); // 注解上指定的角色
                int type = annotation.type();      // 校验的类别方式
                SysUser user = LoginUtil.getLoginUser(tokenValue); //得到当前登录人的权限和角色
                List<String> roleList = user.getRoleList().stream().map(SysRole::getRoleKey).collect(Collectors.toList());
                List<String> permList = LoginUtil.getPermList(tokenValue, Arrays.asList(user.getRoleId()));
                if(type == 0){ // 0： 只校验权限，多个权限需要同时满足；
                    flag = BaseUtil.hasElement(permList, Arrays.asList(perm),true);
                }else if(type == 1){ // 1： 只校验权限，多个权限满足一个即可；
                    flag = BaseUtil.hasElement(permList, Arrays.asList(perm),false);
                }else if(type == 2){ // 2： 只校验角色，多个角色需要同时满足；
                    flag = BaseUtil.hasElement(roleList, Arrays.asList(role),true);
                }else if(type == 3){ // 3： 只校验角色，多个角色满足一个即可；
                    flag = BaseUtil.hasElement(roleList, Arrays.asList(role),false);
                }else if(type == 4){ // 4： 校验权限和角色，需要权限和角色同时满足；
                    flag = BaseUtil.hasElement(permList, Arrays.asList(perm),true);
                    if (flag){ // 满足权限时再校验角色，否则直接返回false
                        flag = BaseUtil.hasElement(roleList, Arrays.asList(role),true);
                    }
                }else if(type == 5){ // 5： 校验权限和角色，权限和角色任意满足一个；
                    flag = BaseUtil.hasElement(permList, Arrays.asList(perm),true);
                    if (!flag){ // 不满足权限时再校验角色，否则直接返回true
                        flag = BaseUtil.hasElement(roleList, Arrays.asList(role),true);
                    }
                }
            }
        }
        return flag;
    }
}
